package com.huatai.common.utils;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 增强 StringUtil的填充字符串的功能，专门处理一些包含中文的字符串
 * 
 */
public class StringUtil {

	/** LOGGER */
	private static final Logger logger = LoggerFactory.getLogger(StringUtil.class);

	private static final BitSet ALPHA = new BitSet(256);
	private static final BitSet ALPHANUM;
	private static final BitSet MARK;
	private static final BitSet RESERVED;
	private static final BitSet UNRESERVED;
	private static int[] HEXADECIMAL;

	static {
		for (int i = 97; i <= 122; i++) {
			ALPHA.set(i);
		}

		for (int i = 65; i <= 90; i++) {
			ALPHA.set(i);
		}

		ALPHANUM = new BitSet(256);

		ALPHANUM.or(ALPHA);

		for (int i = 48; i <= 57; i++) {
			ALPHANUM.set(i);
		}

		MARK = new BitSet(256);

		MARK.set(45);
		MARK.set(95);
		MARK.set(46);
		MARK.set(33);
		MARK.set(126);
		MARK.set(42);
		MARK.set(39);
		MARK.set(40);
		MARK.set(41);

		RESERVED = new BitSet(256);

		RESERVED.set(59);
		RESERVED.set(47);
		RESERVED.set(63);
		RESERVED.set(58);
		RESERVED.set(64);
		RESERVED.set(38);
		RESERVED.set(61);
		RESERVED.set(43);
		RESERVED.set(36);
		RESERVED.set(44);

		UNRESERVED = new BitSet(256);

		UNRESERVED.or(ALPHANUM);
		UNRESERVED.or(MARK);

		HEXADECIMAL = new int[] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70 };
	}

	public static final String EMPTY_STRING = "";

	/** 判断字符串是否为16进制数字 */
	public static final Pattern HAX_PATTERN = Pattern.compile("^[0-9a-fA-F]+$");

	/** 判断字符串是否为数字 */
	public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9]+$");

	/** 默认中文编码字符集 */
	public static final String DEFAULT_CHINESE_CHARSET = "GBK";

	/**
	 * 扩展并左对齐字符串，用指定字符串填充右边。 新增对中文字符串的支持，注意方法名称为<code>alignLeft<b>s</b></code>
	 * 
	 * <pre>
	 * StringUtil.alignLeft(null, *, *)      = null
	 * StringUtil.alignLeft("", 3, "z")      = "zzz"
	 * StringUtil.alignLeft("bat", 3, "yz")  = "bat"
	 * StringUtil.alignLeft("bat", 5, "yz")  = "batyz"
	 * StringUtil.alignLeft("bat", 8, "yz")  = "batyzyzy"
	 * StringUtil.alignLeft("bat", 1, "yz")  = "bat"
	 * StringUtil.alignLeft("bat", -1, "yz") = "bat"
	 * StringUtil.alignLeft("bat", 5, null)  = "bat  "
	 * StringUtil.alignLeft("bat", 5, "")    = "bat  "
	 * StringUtil.alignLeft("中文", 5, "")    = "中文 "
	 * </pre>
	 * 
	 * @param str
	 *            要对齐的字符串
	 * @param size
	 *            扩展字符串到指定宽度
	 * @param padStr
	 *            填充字符串
	 * 
	 * @return 扩展后的字符串，如果字符串为<code>null</code>，则返回<code>null</code>
	 */
	public static String alignLefts(String str, int size, String padStr) {
		if (str == null) {
			return null;
		}

		String padStringFinal = (isEmpty(padStr)) ? EMPTY_STRING : padStr;
		int padLen = padStringFinal.length();
		int strLen = str.getBytes().length;
		int pads = size - strLen;

		if (pads <= 0) {
			return str;
		}

		if (pads == padLen) {
			return str.concat(padStringFinal);
		} else if (pads < padLen) {
			return str.concat(padStringFinal.substring(0, pads));
		} else {
			char[] padding = new char[pads];
			char[] padChars = padStringFinal.toCharArray();

			for (int i = 0; i < pads; i++) {
				padding[i] = padChars[i % padLen];
			}

			return str.concat(new String(padding));
		}
	}

	public static boolean isEmpty(String str) {
		return (str == null) || (str.length() == 0);
	}

	/**
	 * 中午GBK格式编码方式发送
	 * 
	 * @param str
	 * @param size
	 * @param padStr
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String alignLeftsChina(String str, int size, String padStr) throws UnsupportedEncodingException {
		if (str == null) {
			return null;
		}

		String padStringFinal = (isEmpty(padStr)) ? "" : padStr;
		int padLen = padStringFinal.length();
		int strLen = str.getBytes("GBK").length;
		int pads = size - strLen;

		if (pads <= 0) {
			return str;
		}

		if (pads == padLen) {
			return str.concat(padStringFinal);
		} else if (pads < padLen) {
			return str.concat(padStringFinal.substring(0, pads));
		} else {
			char[] padding = new char[pads];
			char[] padChars = padStringFinal.toCharArray();

			for (int i = 0; i < pads; i++) {
				padding[i] = padChars[i % padLen];
			}

			return str.concat(new String(padding));
		}
	}

	/**
	 * 扩展并右对齐字符串，用指定字符串填充左边。 新增对中文字符串的支持，注意方法名称为<code>alignRight<b>s</b></code>
	 * 
	 * <pre>
	 * StringUtil.alignRight(null, *, *)      = null
	 * StringUtil.alignRight("", 3, "z")      = "zzz"
	 * StringUtil.alignRight("bat", 3, "yz")  = "bat"
	 * StringUtil.alignRight("bat", 5, "yz")  = "yzbat"
	 * StringUtil.alignRight("bat", 8, "yz")  = "yzyzybat"
	 * StringUtil.alignRight("bat", 1, "yz")  = "bat"
	 * StringUtil.alignRight("bat", -1, "yz") = "bat"
	 * StringUtil.alignRight("bat", 5, null)  = "  bat"
	 * StringUtil.alignRight("bat", 5, "")    = "  bat"
	 * StringUtil.alignRight("中文", 5, "")    = " 中文"
	 * </pre>
	 * 
	 * @param str
	 *            要对齐的字符串
	 * @param size
	 *            扩展字符串到指定宽度
	 * @param padStr
	 *            填充字符串
	 * 
	 * @return 扩展后的字符串，如果字符串为<code>null</code>，则返回<code>null</code>
	 */
	public static String alignRights(String str, int size, String padStr) {
		if (str == null) {
			return null;
		}

		String padStringFinal = (isEmpty(padStr)) ? EMPTY_STRING : padStr;
		int padLen = padStringFinal.length();
		int strLen = str.getBytes().length;
		int pads = size - strLen;
		if (pads <= 0) {
			return str;
		}

		if (pads == padLen) {
			return padStringFinal.concat(str);
		} else if (pads < padLen) {
			return padStringFinal.substring(0, pads).concat(str);
		} else {
			char[] padding = new char[pads];
			char[] padChars = padStringFinal.toCharArray();

			for (int i = 0; i < pads; i++) {
				padding[i] = padChars[i % padLen];
			}

			return new String(padding).concat(str);
		}
	}

	/**
	 * 取指定字符串的子串，新增对中文字符串的支持 注意方法名称为<code>substring<b>s</b></code>
	 * 
	 * @param str
	 *            字符串
	 * @param start
	 *            起始索引，如果为负数，表示从尾部计算
	 * @param end
	 *            结束索引（不含），如果为负数，表示从尾部计算
	 * 
	 * @return 子串，如果原始串为<code>null</code>，则返回<code>null</code>
	 */
	public static String substrings(String str, int start, int end) {
		if (str == null) {
			return null;
		}

		int length = end - start;
		byte[] dest = new byte[length];
		System.arraycopy(str.getBytes(), start, dest, 0, length);

		return new String(dest);
	}

	/**
	 * 取指定字符串的子串，新增对中文字符串的支持 注意方法名称为<code>substring<b>s</b></code>
	 * 
	 * @param str
	 *            字符串
	 * @param start
	 *            起始索引，如果为负数，表示从尾部计算
	 * @param end
	 *            结束索引（不含），如果为负数，表示从尾部计算
	 * 
	 * @return 子串，如果原始串为<code>null</code>，则返回<code>null</code>
	 */
	public static String substrings(String str, int start, int end, String charSet) {
		String returnStr = null;
		try {
			if (str == null) {
				return null;
			}

			int length = end - start;
			byte[] dest = new byte[length];
			if (StringUtils.isNotEmpty(charSet)) {
				System.arraycopy(str.getBytes(charSet), start, dest, 0, length);
				returnStr = new String(dest, charSet);
			} else {
				System.arraycopy(str.getBytes(), start, dest, 0, length);
				returnStr = new String(dest);
			}
		} catch (UnsupportedEncodingException e) {
			// ExceptionUtil.caught(e,);
			logger.error("不支持的encoding:" + charSet, e);
		}
		return returnStr;
	}

	/**
	 * 根据长度<code>length</code>把字符串切成两段，保存数组<br>
	 * 确保中文不要被切成两半
	 * 
	 * @param message
	 * @param length
	 * @return
	 */
	public static String[] cutString(String message, int length) {
		String normal = StringUtil.substrings(message, 0, length);
		if (isContainChinese(message, length)) {
			normal = StringUtil.substrings(message, 0, length - 1);
		}

		return new String[] { normal, StringUtil.substringAfter(message, normal) };
	}

	public static String substringAfter(String str, String separator) {
		if ((str == null) || (str.length() == 0)) {
			return str;
		}

		if (separator == null) {
			return "";
		}

		int pos = str.indexOf(separator);

		if (pos == -1) {
			return "";
		}

		return str.substring(pos + separator.length());
	}

	/**
	 * 字符串是否包含中文
	 * 
	 * @param message
	 * @param length
	 * @return
	 */
	public static boolean isContainChinese(String message) {
		char[] chars = message.toCharArray();
		byte[] bytes;
		try {
			bytes = message.getBytes("GBK");
		} catch (UnsupportedEncodingException e) {
			logger.error("不支持的encoding: GBK", e);
			bytes = message.getBytes();
		}
		return (chars.length != bytes.length);
	}

	/**
	 * 字符串起始长度<code>length</code>的字符串是否包含中文
	 * 
	 * @param message
	 * @param length
	 * @return
	 */
	public static boolean isContainChinese(String message, int length) {
		char[] chars = StringUtil.substrings(message, 0, length).toCharArray();
		char[] charsPlus = StringUtil.substrings(message, 0, length + 1).toCharArray();
		return ArrayUtils.isSameLength(chars, charsPlus);
	}

	/**
	 * 在字符串中查找指定字符集合中的字符，并返回第一个匹配的起始索引。 如果字符串为<code>null</code>，则返回
	 * <code>-1</code>。 如果字符集合为<code>null</code>或空，也返回<code>-1</code>。
	 * 
	 * <pre>
	 * StringUtil.indexOfAny(null, *,0)                = -1
	 * StringUtil.indexOfAny("", *,0)                  = -1
	 * StringUtil.indexOfAny(*, null,0)                = -1
	 * StringUtil.indexOfAny(*, [],0)                  = -1
	 * StringUtil.indexOfAny("zzabyycdxx",['z','a'],0) = 0
	 * StringUtil.indexOfAny("zzabyycdxx",['b','y'],0) = 3
	 * StringUtil.indexOfAny("aba", ['z'],0)           = -1
	 * </pre>
	 * 
	 * @param str
	 *            要扫描的字符串
	 * @param searchChars
	 *            要搜索的字符集合
	 * @param startPos
	 *            开始搜索的索引值，如果小于0，则看作0
	 * 
	 * @return 第一个匹配的索引值。如果字符串为<code>null</code>或未找到，则返回<code>-1</code>
	 */
	public static int indexOfAny(String str, char[] searchChars, int startPos) {
		if ((str == null) || (str.length() == 0) || (searchChars == null) || (searchChars.length == 0)) {
			return -1;
		}

		for (int i = startPos; i < str.length(); i++) {
			char ch = str.charAt(i);

			for (int j = 0; j < searchChars.length; j++) {
				if (searchChars[j] == ch) {
					return i;
				}
			}
		}

		return -1;
	}

	/**
	 * 过滤要输出到json的字符串，将'和"进行转义输出
	 * 
	 * @param input
	 * @return
	 */
	public static String filterJsonString(String input) {
		if (input == null) {
			return EMPTY_STRING;
		}
		int length = input.length();
		StringBuilder result = new StringBuilder(length);
		for (int i = 0; i < length; i++) {
			char c = input.charAt(i);
			switch (c) {
			case '\'':
				result.append("\\'");
				break;
			case '\"':
				result.append("\\\"");
				break;
			default:
				result.append(c);
			}
		}
		return result.toString();
	}

	/**
	 * 过滤要输出到xml的字符串，将<,>,&,"进行转义输出
	 * 
	 * @param string
	 * @return
	 */
	public static String filterXMLString(String input) {
		if (input == null) {
			return EMPTY_STRING;
		}
		int length = input.length();
		StringBuilder result = new StringBuilder(length);
		for (int i = 0; i < length; i++) {
			char c = input.charAt(i);
			switch (c) {
			case '<': {
				result.append("&lt;");
				break;
			}
			case '>': {
				result.append("&gt;");
				break;
			}
			case '\"': {
				result.append("&uot;");
				break;
			}
			case '&': {
				result.append("&amp;");
				break;
			}
			default: {
				result.append(c);
			}
			}
		}
		return result.toString();
	}

	/**
	 * 根据url获取系统名称 如果url里面包括系统名就返回，否则直接返回域名 如http://bops.pinganfu.com 返回bops
	 * http://www.pinganfu.com 返回 pinganfu.com
	 * 
	 * @param url
	 * @return
	 * @throws MalformedURLException
	 */
	public static String getSystemNameByURL(String url) throws MalformedURLException {
		URL netURL = new URL(url);
		String domain = netURL.getHost();
		if (domain.startsWith("www.")) {
			domain = domain.substring(5);
		}
		int offset = domain.indexOf("pinganfu");
		if (offset > 0) {
			return domain.substring(0, offset - 1);
		} else {
			return domain;
		}
	}

	/**
	 * 在字符串的左边填充长度信息，根据长度的长度定义，采用左补零右对齐的方式
	 * 
	 * @param input
	 * @param lengthLength
	 * @return
	 */
	public static String fillLength(String input, int lengthLength) {
		if (isBlank(input)) {
			return StringUtil.alignRights(EMPTY_STRING, lengthLength, "0");
		}

		String length = Integer.toString(input.getBytes().length);
		String filledLength = StringUtil.alignRight(length, lengthLength, "0");
		return filledLength + input;
	}

	public static String fillLength(String input, String charset, int lengthLength) {
		if (isBlank(input)) {
			return StringUtil.alignRights(EMPTY_STRING, lengthLength, "0");
		}

		String length = null;

		try {
			length = Integer.toString(input.getBytes(charset).length);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		String filledLength = StringUtil.alignRight(length, lengthLength, "0");
		return filledLength + input;
	}

	public static String alignRight(String str, int size) {
		return alignRight(str, size, ' ');
	}

	public static String alignRight(String str, int size, char padChar) {
		if (str == null) {
			return null;
		}

		int pads = size - str.length();

		if (pads <= 0) {
			return str;
		}

		return alignRight(str, size, String.valueOf(padChar));
	}

	public static String alignRight(String str, int size, String padStr) {
		if (str == null) {
			return null;
		}

		if ((padStr == null) || (padStr.length() == 0)) {
			padStr = " ";
		}

		int padLen = padStr.length();
		int strLen = str.length();
		int pads = size - strLen;

		if (pads <= 0) {
			return str;
		}

		if (pads == padLen)
			return padStr.concat(str);
		if (pads < padLen) {
			return padStr.substring(0, pads).concat(str);
		}
		char[] padding = new char[pads];
		char[] padChars = padStr.toCharArray();

		for (int i = 0; i < pads; i++) {
			padding[i] = padChars[(i % padLen)];
		}

		return new String(padding).concat(str);
	}

	/**
	 * 获取指定字符串按GBK编码转换成的byte长度 由于String.getByte方法依赖于操作系统编码，处理中文字符串时建议用此方法
	 * 
	 * @param data
	 * @return
	 */
	public static byte[] getGBKByte(String data) {
		if (data == null) {
			return new byte[0];
		}
		try {
			return data.getBytes("GBK");
		} catch (UnsupportedEncodingException e) {
			logger.error("不支持的Encoding: GBK", e);
			return data.getBytes();
		}
	}

	/**
	 * 获取指定字符串按GBK编码转换成byte的长度 由于String.getByte方法依赖于操作系统编码，处理中文字符串时建议用此方法
	 * 
	 * @param data
	 * @return
	 */
	public static int getGBKByteLength(String data) {
		return getGBKByte(data).length;
	}

	/**
	 * 生成一定长度的序列号
	 * 
	 * @param length
	 * @param padding
	 * @return
	 */
	public static String genSerialNo(int length, String padding) {
		String nanoTime = System.nanoTime() + "";
		if (nanoTime.length() >= length) {
			nanoTime = nanoTime.substring(0, length);
		} else {
			nanoTime = nanoTime + repeat(padding, length - nanoTime.length());
		}
		return nanoTime;
	}

	public static String repeat(String str, int repeat) {
		if (str == null) {
			return null;
		}

		if (repeat <= 0) {
			return "";
		}

		int inputLength = str.length();

		if ((repeat == 1) || (inputLength == 0)) {
			return str;
		}

		int outputLength = inputLength * repeat;

		switch (inputLength) {
		case 1:
			char ch = str.charAt(0);
			char[] output1 = new char[outputLength];

			for (int i = repeat - 1; i >= 0; i--) {
				output1[i] = ch;
			}

			return new String(output1);
		case 2:
			char ch0 = str.charAt(0);
			char ch1 = str.charAt(1);
			char[] output2 = new char[outputLength];

			for (int i = (repeat * 2) - 2; i >= 0; i--) {
				output2[i] = ch0;
				output2[(i + 1)] = ch1;

				i--;
			}

			return new String(output2);
		}

		StringBuilder buf = new StringBuilder(outputLength);

		for (int i = 0; i < repeat; i++) {
			buf.append(str);
		}

		return buf.toString();
	}

	/**
	 * 将数字格式化到固定长度
	 * 
	 * @param input
	 * @param fixLength
	 * @return
	 */
	public static String formatNumberToFixedLength(String input, int fixLength) {
		if (input.length() <= fixLength) {
			// 未到指定长度，左补0
			return alignRight(input, fixLength, '0');
		} else {
			// 超过长度，砍掉左边超长部分
			return input.substring(input.length() - fixLength);
		}
	}

	/**
	 * 判断字符串是否为16进制数字
	 * 
	 * @param input
	 * @return
	 */
	public static boolean isHexString(String input) {
		if (input == null) {
			return false;
		}
		if (NUMBER_PATTERN.matcher(input).matches()) {
			// 过滤掉纯数字
			return false;
		}
		return HAX_PATTERN.matcher(input).matches();
	}

	/**
	 * 将byte[]按指定编码转换为字符串，供velocity中使用
	 * 
	 * @param bytes
	 * @param charsetName
	 * @return
	 */
	public static String getNewString(byte[] bytes, String charsetName) {
		try {
			return new String(bytes, charsetName);
		} catch (UnsupportedEncodingException e) {
			logger.warn("不支持的编码", e);
			return EMPTY_STRING;
		}
	}

	public static boolean isBlank(String str) {
		int length;
		if ((str == null) || ((length = str.length()) == 0)) {
			return true;
		}

		for (int i = 0; i < length; i++) {
			if (!Character.isWhitespace(str.charAt(i))) {
				return false;
			}
		}

		return true;
	}

	public static boolean isNotBlank(String str) {
		int length;
		if ((str == null) || ((length = str.length()) == 0)) {
			return false;
		}
		for (int i = 0; i < length; i++) {
			if (!Character.isWhitespace(str.charAt(i))) {
				return true;
			}
		}

		return false;
	}

	public static String left(String str, int len) {
		if (str == null) {
			return null;
		}

		if (len < 0) {
			return "";
		}

		if (str.length() <= len) {
			return str;
		}
		return str.substring(0, len);
	}

	public static String right(String str, int len) {
		if (str == null) {
			return null;
		}

		if (len < 0) {
			return "";
		}

		if (str.length() <= len) {
			return str;
		}
		return str.substring(str.length() - len);
	}

	public static String substringBetween(String str, String tag) {
		return substringBetween(str, tag, tag, 0);
	}

	public static String substringBetween(String str, String open, String close) {
		return substringBetween(str, open, close, 0);
	}

	public static String substringBetween(String str, String open, String close, int fromIndex) {
		if ((str == null) || (open == null) || (close == null)) {
			return null;
		}

		int start = str.indexOf(open, fromIndex);

		if (start != -1) {
			int end = str.indexOf(close, start + open.length());

			if (end != -1) {
				return str.substring(start + open.length(), end);
			}
		}

		return null;
	}

	public static String substringAfterLast(String str, String separator) {
		if ((str == null) || (str.length() == 0)) {
			return str;
		}

		if ((separator == null) || (separator.length() == 0)) {
			return "";
		}

		int pos = str.lastIndexOf(separator);

		if ((pos == -1) || (pos == (str.length() - separator.length()))) {
			return "";
		}

		return str.substring(pos + separator.length());
	}

	public static String trim(String str) {
		return trim(str, null, 0);
	}

	public static String trim(String str, String stripChars) {
		return trim(str, stripChars, 0);
	}

	public static String trimStart(String str) {
		return trim(str, null, -1);
	}

	public static String trimStart(String str, String stripChars) {
		return trim(str, stripChars, -1);
	}

	public static String trimEnd(String str) {
		return trim(str, null, 1);
	}

	public static String trimEnd(String str, String stripChars) {
		return trim(str, stripChars, 1);
	}

	public static String trimToNull(String str) {
		return trimToNull(str, null);
	}

	public static String trimToNull(String str, String stripChars) {
		String result = trim(str, stripChars);

		if ((result == null) || (result.length() == 0)) {
			return null;
		}

		return result;
	}

	public static String trimToEmpty(String str) {
		return trimToEmpty(str, null);
	}

	public static String trimToEmpty(String str, String stripChars) {
		String result = trim(str, stripChars);

		if (result == null) {
			return "";
		}

		return result;
	}

	private static String trim(String str, String stripChars, int mode) {
		if (str == null) {
			return null;
		}

		int length = str.length();
		int start = 0;
		int end = length;

		if (mode <= 0) {
			if (stripChars == null) {
				do {
					start++;

					if (start >= end) {
						break;
					}
				} while (Character.isWhitespace(str.charAt(start)));
			} else {
				if (stripChars.length() == 0) {
					return str;
				}

				do
					start++;
				while ((start < end) && (stripChars.indexOf(str.charAt(start)) != -1));
			}
		}

		if (mode >= 0) {
			if (stripChars == null) {
				do {
					end--;

					if (start >= end) {
						break;
					}
				} while (Character.isWhitespace(str.charAt(end - 1)));
			} else {
				if (stripChars.length() == 0) {
					return str;
				}

				do
					end--;
				while ((start < end) && (stripChars.indexOf(str.charAt(end - 1)) != -1));
			}
		}

		if ((start > 0) || (end < length)) {
			return str.substring(start, end);
		}

		return str;
	}

	public static String defaultIfBlank(String str) {
		return isBlank(str) ? "" : str;
	}

	public static String defaultIfBlank(String str, String defaultStr) {
		return isBlank(str) ? defaultStr : str;
	}

	public static String substringBefore(String str, String separator) {
		if ((str == null) || (separator == null) || (str.length() == 0)) {
			return str;
		}

		if (separator.length() == 0) {
			return "";
		}

		int pos = str.indexOf(separator);

		if (pos == -1) {
			return str;
		}

		return str.substring(0, pos);
	}

	public static String toLowerCase(String str) {
		if (str == null) {
			return null;
		}

		return str.toLowerCase();
	}

	public static boolean equals(String str1, String str2) {
		if (str1 == null) {
			return str2 == null;
		}

		return str1.equals(str2);
	}

	public static boolean equalsIgnoreCase(String str1, String str2) {
		if (str1 == null) {
			return str2 == null;
		}

		return str1.equalsIgnoreCase(str2);
	}

	public static boolean isNotEmpty(String str) {
		return (str != null) && (str.length() > 0);
	}

	public static String defaultIfNull(String str) {
		return str == null ? "" : str;
	}

	public static String defaultIfNull(String str, String defaultStr) {
		return str == null ? defaultStr : str;
	}

	public static String replaceOnce(String text, String repl, String with) {
		return replace(text, repl, with, 1);
	}

	public static String replaceAllByRegex(String text, String rep1, String with) {

		Pattern CRLF = Pattern.compile(rep1);
		Matcher m = CRLF.matcher(text);
		if (m.find()) {
			return m.replaceAll(with);
		} else {
			return text;
		}

	}

	public static String replace(String text, String repl, String with) {
		return replace(text, repl, with, -1);
	}

	public static String replace(String text, String repl, String with, int max) {
		if ((text == null) || (repl == null) || (with == null) || (repl.length() == 0) || (max == 0)) {
			return text;
		}

		StringBuilder buf = new StringBuilder(text.length());
		int start = 0;
		int end = 0;

		while ((end = text.indexOf(repl, start)) != -1) {
			buf.append(text.substring(start, end)).append(with);
			start = end + repl.length();

			max--;
			if (max == 0) {
				break;
			}
		}
		buf.append(text.substring(start));
		return buf.toString();
	}

	public static String replaceChars(String str, char searchChar, char replaceChar) {
		if (str == null) {
			return null;
		}

		return str.replace(searchChar, replaceChar);
	}

	public static String replaceChars(String str, String searchChars, String replaceChars) {
		if ((str == null) || (str.length() == 0) || (searchChars == null) || (searchChars.length() == 0)) {
			return str;
		}

		char[] chars = str.toCharArray();
		int len = chars.length;
		boolean modified = false;

		int i = 0;
		for (int isize = searchChars.length(); i < isize; i++) {
			char searchChar = searchChars.charAt(i);

			if ((replaceChars == null) || (i >= replaceChars.length())) {
				int pos = 0;

				for (int j = 0; j < len; j++) {
					if (chars[j] != searchChar) {
						chars[(pos++)] = chars[j];
					} else {
						modified = true;
					}
				}

				len = pos;
			} else {
				for (int j = 0; j < len; j++) {
					if (chars[j] == searchChar) {
						chars[j] = replaceChars.charAt(i);
						modified = true;
					}
				}
			}
		}

		if (!modified) {
			return str;
		}

		return new String(chars, 0, len);
	}

	public static String toUpperCase(String str) {
		if (str == null) {
			return null;
		}

		return str.toUpperCase();
	}

	public static boolean isNumeric(String str) {
		if (str == null) {
			return false;
		}

		int length = str.length();

		for (int i = 0; i < length; i++) {
			if (!Character.isDigit(str.charAt(i))) {
				return false;
			}
		}

		return true;
	}

	public static boolean isNumericSpace(String str) {
		if (str == null) {
			return false;
		}

		int length = str.length();

		for (int i = 0; i < length; i++) {
			if ((!Character.isDigit(str.charAt(i))) && (str.charAt(i) != ' ')) {
				return false;
			}
		}

		return true;
	}

	public static String substring(String str, int start, int end) {
		if (str == null) {
			return null;
		}

		if (end < 0) {
			end = str.length() + end;
		}

		if (start < 0) {
			start = str.length() + start;
		}

		if (end > str.length()) {
			end = str.length();
		}

		if (start > end) {
			return "";
		}

		if (start < 0) {
			start = 0;
		}

		if (end < 0) {
			end = 0;
		}

		return str.substring(start, end);
	}

	public static boolean contains(String str, char searchChar) {
		if ((str == null) || (str.length() == 0)) {
			return false;
		}

		return str.indexOf(searchChar) >= 0;
	}

	public static boolean contains(String str, String searchStr) {
		if ((str == null) || (searchStr == null)) {
			return false;
		}

		return str.indexOf(searchStr) >= 0;
	}

	public static boolean containsOnly(String str, char[] valid) {
		if ((valid == null) || (str == null)) {
			return false;
		}

		if (str.length() == 0) {
			return true;
		}

		if (valid.length == 0) {
			return false;
		}

		return indexOfAnyBut(str, valid) == -1;
	}

	public static boolean containsOnly(String str, String valid) {
		if ((str == null) || (valid == null)) {
			return false;
		}

		return containsOnly(str, valid.toCharArray());
	}

	public static boolean containsNone(String str, char[] invalid) {
		if ((str == null) || (invalid == null)) {
			return true;
		}

		int strSize = str.length();
		int validSize = invalid.length;

		for (int i = 0; i < strSize; i++) {
			char ch = str.charAt(i);

			for (int j = 0; j < validSize; j++) {
				if (invalid[j] == ch) {
					return false;
				}
			}
		}

		return true;
	}

	public static boolean containsNone(String str, String invalidChars) {
		if ((str == null) || (invalidChars == null)) {
			return true;
		}

		return containsNone(str, invalidChars.toCharArray());
	}

	public static int indexOfAnyBut(String str, char[] searchChars) {
		if ((str == null) || (str.length() == 0) || (searchChars == null) || (searchChars.length == 0)) {
			return -1;
		}

		for (int i = 0; i < str.length(); i++) {
			char ch = str.charAt(i);

			int j = 0;
			while (searchChars[j] != ch) {
				j++;
				if (j >= searchChars.length) {
					return i;
				}
			}
		}
		return -1;
	}

	public static int indexOfAnyBut(String str, String searchChars) {
		if ((str == null) || (str.length() == 0) || (searchChars == null) || (searchChars.length() == 0)) {
			return -1;
		}

		for (int i = 0; i < str.length(); i++) {
			if (searchChars.indexOf(str.charAt(i)) < 0) {
				return i;
			}
		}

		return -1;
	}

	public static String escapeURL(String str) {
		return escapeURLInternal(str, null, true);
	}

	public static String escapeURL(String str, String encoding) throws UnsupportedEncodingException {
		return escapeURLInternal(str, encoding, true);
	}

	public static String escapeURL(String str, String encoding, boolean strict) throws UnsupportedEncodingException {
		return escapeURLInternal(str, encoding, strict);
	}

	public static void escapeURL(String str, String encoding, Writer out) throws IOException {
		escapeURLInternal(str, encoding, out, true);
	}

	public static void escapeURL(String str, String encoding, Writer out, boolean strict) throws IOException {
		escapeURLInternal(str, encoding, out, strict);
	}

	private static String escapeURLInternal(String str, String encoding, boolean strict) {
		if (str == null) {
			return null;
		}
		try {
			StringWriter out = new StringWriter(str.length());

			if (escapeURLInternal(str, encoding, out, strict)) {
				return out.toString();
			}

			return str;
		} catch (UnsupportedEncodingException e) {
			logger.warn("不支持的编码", e);
		} catch (IOException e) {
			logger.warn("IO异常", e);
		}
		return str;
	}

	private static boolean escapeURLInternal(String str, String encoding, Writer out, boolean strict)
			throws IOException {

		boolean needToChange = false;

		if (out == null) {
			throw new IllegalArgumentException("The Writer must not be null");
		}

		if (str == null) {
			return needToChange;
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream(10);
		OutputStreamWriter writer = new OutputStreamWriter(baos, encoding);

		for (int i = 0; i < str.length(); i++) {
			int ch = str.charAt(i);

			if (isSafeCharacter(ch, strict)) {
				out.write(ch);
			} else if (ch == 32) {
				out.write(43);

				needToChange = true;
			} else {
				try {
					writer.write(ch);
					writer.flush();
				} catch (IOException e) {
					logger.warn("IO异常", e);
					baos.reset();
					continue;
				}

				byte[] bytes = baos.toByteArray();

				for (int j = 0; j < bytes.length; j++) {
					byte toEscape = bytes[j];

					out.write(37);

					int low = toEscape & 0xF;
					int high = (toEscape & 0xF0) >> 4;

					out.write(HEXADECIMAL[high]);
					out.write(HEXADECIMAL[low]);
				}

				baos.reset();

				needToChange = true;
			}
		}

		return needToChange;
	}

	private static boolean isSafeCharacter(int ch, boolean strict) {
		if (strict) {
			return UNRESERVED.get(ch);
		}
		return (ch > 32) && (!RESERVED.get(ch)) && (!Character.isWhitespace((char) ch));
	}

	public static String defaultIfEmpty(String str) {
		return str == null ? "" : str;
	}

	public static String defaultIfEmpty(String str, String defaultStr) {
		return ((str == null) || (str.length() == 0)) ? defaultStr : str;
	}

	public static String substringBeforeLast(String str, String separator) {
		if ((str == null) || (separator == null) || (str.length() == 0) || (separator.length() == 0)) {
			return str;
		}

		int pos = str.lastIndexOf(separator);

		if (pos == -1) {
			return str;
		}

		return str.substring(0, pos);
	}

	/**
	 * 将Map对象组装成字符串：key=value&key=value
	 * 
	 * @param resultMap
	 * @return
	 */
	public static String concatData(Map<String, String> resultMap) {
		if (null == resultMap || resultMap.isEmpty()) {
			return "";
		}
		StringBuilder buffer = new StringBuilder();
		for (Map.Entry<String, String> map : resultMap.entrySet()) {
			buffer.append(map.getKey()).append("=").append(map.getValue()).append("&");
		}
		buffer.deleteCharAt(buffer.lastIndexOf("&"));
		return buffer.toString();
	}

	/**
	 * 计算字符的字节长度
	 * 
	 * @param str
	 */
	public static String getStrBytes(String str, String ecode) throws Exception {
		int len = 0;
		if (str == null) {
			return "0";
		}
		try {
			len = str.getBytes(ecode).length;
		} catch (UnsupportedEncodingException e) {
			logger.error("不支持的Encoding: " + ecode, e);
			throw new Exception(e + "UnsupportedEncodingException");
		}
		return String.valueOf(len);
	}

	public static Map<String, String> getValues(String str) {

		Map<String, String> valueMap = new HashMap<String, String>();
		if (str.indexOf('&') != -1) {
			String[] strs = str.split("&");
			for (int i = 0; i < strs.length; i++) {
				String[] a = strs[i].split("=", -1);
				valueMap.put(a[0], a[1]);
			}
		}
		return valueMap;
	}

	/**
	 * 获取json对象字符串key值
	 * 
	 * @param src
	 * @param key
	 * @return
	 */
	public static String getJsonValue(String src, String key) {

		String[] keys = key.split("/");
		JSONObject jobject = JSON.parseObject(src);

		for (int i = 0; i < (keys.length - 1); i++) {
			jobject = jobject.getJSONObject(keys[i]);
		}

		return jobject.getString(keys[keys.length - 1]);
	}

	/**
	 * 卡号不足19位的右补空格
	 */
	public static String getPans(String pan) {
		int size = pan.length();
		String result = " ";
		if (size < 19) {
			for (int i = 0; i < (19 - size); i++) {
				pan = pan + result;
			}
		}
		return pan;
	}

	/***
	 * 优先取上游转过来的信息返回，转码返回
	 * 
	 * @param assembleValue
	 *            ---> 上游传过来的值
	 * @param fixedValue
	 *            ---> 指定的值
	 */
	public static String takeNotBlankValue(String assembleValue, String fixedValue, String code) {
		if (isNotBlank(assembleValue)) {
			if ("escape".equals(code)) {
				return escape(assembleValue);
			} else {
				return assembleValue;
			}
		} else {
			if ("escape".equals(code)) {
				return escape(fixedValue);
			} else {
				return fixedValue;
			}
		}
	}

	/***
	 * 转码
	 * 
	 * @param src
	 * @return
	 */
	public static String escape(String src) {
		int i;
		char j;
		StringBuffer tmp = new StringBuffer();
		tmp.ensureCapacity(src.length() * 6);
		for (i = 0; i < src.length(); i++) {
			j = src.charAt(i);
			if (Character.isDigit(j) || Character.isLowerCase(j) || Character.isUpperCase(j)) {
				tmp.append(j);
			} else if (j < 256) {
				tmp.append("%");
				if (j < 16)
					tmp.append("0");
				tmp.append(Integer.toString(j, 16).toUpperCase());
			} else {
				tmp.append("%u");
				tmp.append(Integer.toString(j, 16).toUpperCase());
			}
		}
		return tmp.toString();
	}

	/**
	 * 解码
	 * 
	 * @param src
	 * @return
	 */
	public static String unescape(String src) {
		StringBuffer tmp = new StringBuffer();
		tmp.ensureCapacity(src.length());
		int lastPos = 0, pos = 0;
		char ch;
		while (lastPos < src.length()) {
			pos = src.indexOf("%", lastPos);
			if (pos == lastPos) {
				if (src.charAt(pos + 1) == 'u') {
					ch = (char) Integer.parseInt(src.substring(pos + 2, pos + 6), 16);
					tmp.append(ch);
					lastPos = pos + 6;
				} else {
					ch = (char) Integer.parseInt(src.substring(pos + 1, pos + 3), 16);
					tmp.append(ch);
					lastPos = pos + 3;
				}
			} else {
				if (pos == -1) {
					tmp.append(src.substring(lastPos));
					lastPos = src.length();
				} else {
					tmp.append(src.substring(lastPos, pos));
					lastPos = pos;
				}
			}
		}
		return tmp.toString();
	}

	/**
	 * 连接字符串 主要用于velocity调用
	 * 
	 * @param str1
	 * @param str2
	 * @return
	 */
	public String combineStr(Object str1, Object str2) {
		return String.valueOf(str1) + String.valueOf(str2);
	}

	public String loggerText(String text) {
		logger.info("想要答应的内容：" + text);
		return "";
	}

	public static int getLengthforBCCB(String req) throws Exception {
		System.out.println("the req is:" + req);
		if (req == null) {
			throw new Exception("the req is null");
		} else {
			return req.getBytes("GBK").length;
		}

	}

	public static Map<String, String> getValuesForUNP(String str) {

		Map<String, String> valueMap = new HashMap<String, String>();
		if (str.indexOf('&') != -1) {
			String[] strs = str.split("&");
			for (int i = 0; i < strs.length - 1; i++) {
				String[] a = strs[i].split("=", -1);
				if ("respMsg".equals(a[0])) {
					valueMap.put(a[0], a[1]);
				} else {
					valueMap.put(a[0], a[1]);
				}
			}
			String b = strs[strs.length - 1].substring(0, 8);
			String c = strs[strs.length - 1].substring(9);
			valueMap.put(b, c);
		}
		return valueMap;
	}

	public static String getLengthForICBCSZZH(String str) {
		int len = str.getBytes().length;
		return "" + ((len >>> 24) & 0xFF) + ((len >>> 16) & 0xFF) + ((len >>> 8) & 0xFF) + ((len >>> 0) & 0xFF);
	}

	public static String subLeft(String str, int num) {
		return str.substring(0, num);
	}

	public static String subRight(String str, int num) {
		return str.substring(str.length() - num, str.length());
	}

}
